// 坦克接口
interface ITank {
    fire(): void;
}
let t1: ITank = {
    fire() {
        console.log('发射机关枪');
    }
}
t1.fire();// 发射机关枪
// 开火装饰器
function fireDecorators(obj: any) {
    obj.fire = function () {
        console.log('发射大炮');
    };
}
fireDecorators(t1);
t1.fire();// 发射大炮


// 装饰函数1
// 又长又古老的函数
function oldFunction() {
    console.log('这是一个老旧的函数，里面可能装了非常多的老旧的逻辑，内部的实现你甚至不想看。');
}
// 保存原函数的引用
const __oldFunction = oldFunction;
// 通过装饰器模式新改写的函数，你甚至可以覆盖原本的函数名
function newFunction() {
    __oldFunction();
    console.log('这部分的逻辑是后来装饰上的...实际上我们并没有改动原函数的逻辑');
}

// 测试用例
newFunction();

// AOP
// 装饰功能在原函数之前
function beforeDecorator(preFunc: Function, addBehave: Function) {
    return function (this: any, ...params: any[]) {
        addBehave.apply(this, params);
        return preFunc.apply(this, params);
    };
}
// 装饰功能在原函数之后
function afterDecorator(preFunc: Function, addBehave: Function) {
    return function (this: any, ...params: any[]) {
        preFunc.apply(this, params);
        return addBehave.apply(this, params);
    };
}

// 测试用例
let beforeD = beforeDecorator(() => {
    console.log(3);
    console.log(4);
}, () => {
    console.log(1);
    console.log(2);
});
beforeD();// 1 2 3 4

let afterD = afterDecorator((a: string) => {
    console.log(1);
    console.log(a);
}, () => {
    console.log(2);
});
afterD('这是个传入的参数');// 1 这是个传入的参数 2


// 装饰函数的应用例子
const btn = document.getElementById('clickBtn');
// 处理点击按钮的逻辑
function handleClick() {
    alert('这里执行了一段业务逻辑，例如说上传资料...');
};

// 装饰器模式后
function afterDecorator2(fn: Function, addLogic: Function) {
    return function (this: any, ...params: any[]) {
        fn.apply(this, params);
        return addLogic.apply(this, params);
    }
}

let sum = 0;// 总的点击次数
btn?.addEventListener('click', afterDecorator(handleClick, () => {
    sum++;
    console.log(sum);
}));

// 表单验证的逻辑
// 抓DOM
const username = document.getElementById('username');
const password = document.getElementById('psw');
const submit = document.querySelector('input[type=submit]');
// 验证表单元素
function checkInputElem(elem: unknown): elem is HTMLInputElement {
    return Object.prototype.toString.call(elem) === '[object HTMLInputElement]';
}
// 验证逻辑
function checkBeforeSubmit() {
    if (checkInputElem(username) && username.value === '') {
        alert('用户名不能为空');
        return;
    }
    if (checkInputElem(password) && password.value === '') {
        alert('密码不能为空');
        return;
    }
    alert('成功的提交了请求');
}
// submit?.addEventListener('click', checkBeforeSubmit);

// 使用装饰器模式改造
function beforeDec(fn: Function, addLogic: BooleanFunction) {
    return function (this: any, ...params: any[]) {
        if (!addLogic.apply(this, params)) {
            return;
        }
        return fn.apply(this, params);
    }
}
// 验证参数合理性函数
function inputValidation(): boolean {
    if (checkInputElem(username) && username.value === '') {
        alert('用户名不能为空');
        return false;
    }
    if (checkInputElem(password) && password.value === '') {
        alert('密码不能为空');
        return false;
    }
    return true;
}
// 提交函数
function inputSubmit() {
    alert('成功的提交了请求');
}

// 重新改造后
submit?.addEventListener('click', beforeDec(inputSubmit, inputValidation));
